/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package DAO;

import Common.Constants;
import Common.GeneralHandling;
import POJO.TagNameAndCounter;
import POJO.TagPOJO;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.cassandra.thrift.*;
import org.apache.thrift.TException;
import SearchSolr.solrSearch;

/**
 *
 * @author node1
 */
public class TagDAO {

    public static ByteBuffer colParentTagInfo = ByteBuffer.wrap("TagInfo".getBytes());
    public static ByteBuffer colParentListStatus = ByteBuffer.wrap("TagListStatus".getBytes());
    public static ByteBuffer colNameCreateDate = ByteBuffer.wrap("createDate".getBytes());
    public static ByteBuffer colNameModifyDate = ByteBuffer.wrap("modifyDate".getBytes());
    public static ByteBuffer colNameIsPublic = ByteBuffer.wrap("state".getBytes());
    public static String colParentTagInfoS = "TagInfo";
    public static String colParentListStatusS = "TagListStatus";
    public static String colNameCreateDateS = "createDate";
    public static String colNameModifyDateS = "modifyDate";
    public static String colNameIsPublicS = "state";
    private static Cassandra.Client client;
    private static TagDAO instance;

    public static TagDAO getInstance(Cassandra.Client _client) {
        if (instance != null) {
            return instance;
        }
        instance = new TagDAO();
        client = _client;
        return instance;
    }

    public void createCacheTag(List<String> listMem) {
        if (!cachedAllTagNameAndCounter(listMem)) {
            System.out.println("Không thể tạo cached");
        }
    }

    public TagPOJO selectTagWithTagName(String tagName) {
        TagPOJO result = new TagPOJO();
        try {
            //Lay thong tin Tag tu TagInfo
            ByteBuffer tagNameBB = Common.GeneralHandling.toByteBuffer(tagName);
            ColumnParent parent = new ColumnParent(colParentTagInfoS);

            SlicePredicate predicate = createSlicePredicateForTag();

            List<ColumnOrSuperColumn> listColOrSupCol = client.get_slice(tagNameBB, parent, predicate, Common.Constants.CL);
            if(!listColOrSupCol.isEmpty()){
                result = createTagPOJOFromListColOrSupCol(tagName, listColOrSupCol);
            }else{
                result.tagName = "-1";
            }
            
            //Lay danh sach status thuoc Tag
            parent = new ColumnParent(colParentListStatusS);
            predicate = new SlicePredicate();
            SliceRange sliceRange = new SliceRange();
            sliceRange.start = GeneralHandling.toByteBuffer("");
            sliceRange.finish = GeneralHandling.toByteBuffer("");
            predicate.slice_range = sliceRange;

            listColOrSupCol = client.get_slice(tagNameBB, parent, predicate, Common.Constants.CL);
            result.listStatusID = getListStringStatusFromListColOrSupCol(listColOrSupCol);

        } catch (InvalidRequestException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnavailableException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TimedOutException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return result;
    }

    public List<TagPOJO> selectListTag(int limit) {
        List<TagPOJO> listTag = new ArrayList<TagPOJO>();
        try {
            ColumnParent parent = new ColumnParent(colParentTagInfoS);
            SlicePredicate predicate = createSlicePredicateForTag();

            KeyRange range = new KeyRange();
            range.start_key = Common.GeneralHandling.toByteBuffer("");
            range.end_key = Common.GeneralHandling.toByteBuffer("");
            range.count = limit;
            List<KeySlice> listKeySlice = client.get_range_slices(parent, predicate, range, Common.Constants.CL);
            for (KeySlice keySlice : listKeySlice) {
                TagPOJO temp = selectTagWithTagName(GeneralHandling.toString(keySlice.key));
                if (temp.getTagName() != null) {
                    listTag.add(temp);
                }
            }
        } catch (TException ex) {
            Logger.getLogger(TagDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidRequestException ex) {
            Logger.getLogger(TagDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnavailableException ex) {
            Logger.getLogger(TagDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TimedOutException ex) {
            Logger.getLogger(TagDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(TagDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return listTag;
    }

    public List<TagPOJO> selectAllTag() {
        List<TagPOJO> listTag = new ArrayList<TagPOJO>();
        try {
            ColumnParent parent = new ColumnParent(colParentTagInfoS);
            SlicePredicate predicate = createSlicePredicateForTag();

            KeyRange range = new KeyRange();
            range.start_key = Common.GeneralHandling.toByteBuffer("");
            range.end_key = Common.GeneralHandling.toByteBuffer("");
            range.count = Short.MAX_VALUE;
            List<KeySlice> listKeySlice = client.get_range_slices(parent, predicate, range, Common.Constants.CL);
            for (KeySlice keySlice : listKeySlice) {
                TagPOJO temp = selectTagWithTagName(GeneralHandling.toString(keySlice.key));
                if (temp.getTagName() != null && temp.getTagName() != "-1") {
                    listTag.add(temp);
                }
            }
        } catch (TException ex) {
            Logger.getLogger(TagDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidRequestException ex) {
            Logger.getLogger(TagDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnavailableException ex) {
            Logger.getLogger(TagDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TimedOutException ex) {
            Logger.getLogger(TagDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(TagDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return listTag;
    }

    public List<TagNameAndCounter> selectAllTagNameAndCounter() {
        List<TagNameAndCounter> listTagNameAndCounter = new ArrayList<TagNameAndCounter>();
        List<TagPOJO> listTagPOJO = selectAllTag();
        int numberTag = listTagPOJO.size();
        for (int i = 0; i < numberTag; i++) {
            TagNameAndCounter tag = new TagNameAndCounter(listTagPOJO.get(i).tagName, listTagPOJO.get(i).listStatusID.size());
            listTagNameAndCounter.add(tag);
        }
        Memcached.set("AllTagNameAndCounter", Constants.EXPIRE, listTagNameAndCounter);
        return listTagNameAndCounter;
    }

    public boolean cachedAllTagNameAndCounter(List<String> listMem) {
        List<TagNameAndCounter> listTagNameAndCounter = new ArrayList<TagNameAndCounter>();
        List<TagPOJO> listTagPOJO = selectAllTag();
        int numberTag = listTagPOJO.size();
        for (int i = 0; i < numberTag; i++) {
            TagNameAndCounter tag = new TagNameAndCounter(listTagPOJO.get(i).tagName, listTagPOJO.get(i).listStatusID.size());
            listTagNameAndCounter.add(tag);
        }
        Memcached.set("AllTagNameAndCounter", Constants.EXPIRE, listTagNameAndCounter);
        listMem.add("AllTagNameAndCounter");
        return true;
    }

    public boolean cachedAllTagNameAndCounter() {
        List<TagNameAndCounter> listTagNameAndCounter = new ArrayList<TagNameAndCounter>();
        List<TagPOJO> listTagPOJO = selectAllTag();
        int numberTag = listTagPOJO.size();
        for (int i = 0; i < numberTag; i++) {
            TagNameAndCounter tag = new TagNameAndCounter(listTagPOJO.get(i).tagName, listTagPOJO.get(i).listStatusID.size());
            listTagNameAndCounter.add(tag);
        }
        Memcached.set("AllTagNameAndCounter", Constants.EXPIRE, listTagNameAndCounter);
        return true;
    }

    public boolean removeStatusInATag(String tagName, String statusID) {
        boolean result = false;
        try {
            ColumnParent parent = new ColumnParent(colParentListStatusS);
            ByteBuffer tagNameBB = Common.GeneralHandling.toByteBuffer(tagName);
            client.insert(tagNameBB, parent, Common.GeneralHandling.createCol(GeneralHandling.toByteBuffer(statusID), "0"), Common.Constants.CL);
            result = true;
        } catch (InvalidRequestException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnavailableException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TimedOutException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return result;
    }

    public List<TagNameAndCounter> selectTagNameAndCounter(int limit) {
        List<TagNameAndCounter> listTagNameAndCounter = new ArrayList<TagNameAndCounter>();
        List<TagPOJO> listTagPOJO = selectListTag(limit);
        int numberTag = listTagPOJO.size();
        for (int i = 0; i < numberTag; i++) {
            TagNameAndCounter tag = new TagNameAndCounter(listTagPOJO.get(i).tagName, listTagPOJO.get(i).listStatusID.size());
            listTagNameAndCounter.add(tag);
        }
        return listTagNameAndCounter;
    }

    public boolean updateIsPublicOnATag(String tagName, boolean state) throws Exception {
        boolean result = false;
        try {
            String isPublic = (state == true) ? "public" : "private";
            ColumnParent parent = new ColumnParent(colParentTagInfoS);
            ByteBuffer tagNameBB = Common.GeneralHandling.toByteBuffer(tagName);
            client.insert(tagNameBB, parent, Common.GeneralHandling.createCol(colNameIsPublic, isPublic), Common.Constants.CL);
            result = true;
        } catch (InvalidRequestException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnavailableException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TimedOutException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return result;
    }

    public int updateIsPublicOnListTag(List<String> listTagName, boolean state) throws Exception {
        int result = 0;
        for (String tagName : listTagName) {
            updateIsPublicOnATag(tagName, state);
            result++;
        }
        return result;
    }

    public boolean insertStatusIntoTag(String statusID, String tagName) {
        boolean result = false;
        try {
            ColumnParent parent = new ColumnParent(colParentListStatusS);
            ByteBuffer tagNameBB = Common.GeneralHandling.toByteBuffer(tagName);
            client.insert(tagNameBB, parent, Common.GeneralHandling.createCol(GeneralHandling.toByteBuffer(statusID), "1"), Common.Constants.CL);
            result = true;
        } catch (InvalidRequestException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnavailableException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TimedOutException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return result;
    }

    public boolean deleteTag(String tagName) throws Exception {
        boolean result = false;
        TagPOJO tag = selectTagWithTagName(tagName);

        //Lay danh sach status trong Tag de cap nhat lai.
        if (!tag.listStatusID.isEmpty()) {
            for (int i = 0; i < tag.listStatusID.size(); i++) {
                //Goi phuong thuc UpdatelistTag de loai bo tag trong status tuong ung.
                StatusDAO stt = StatusDAO.getInstance(client);
                stt.removeTagInListTagOnAStatus(tag.listStatusID.get(i), tagName);
                result = true;
            }
        }

        //Remove Tag hien hanh
        ByteBuffer rowKey = GeneralHandling.toByteBuffer(tagName);
        ColumnPath path = new ColumnPath(colParentTagInfoS);
        client.remove(rowKey, path, System.currentTimeMillis(), Constants.CL);
        path = new ColumnPath(colParentListStatusS);
        client.remove(rowKey, path, System.currentTimeMillis(), Constants.CL);
        CounterDAO.Decrease(CounterDAO.colNameTag, client);
        return result;
    }

    public boolean deleteListTag(List<String> listTagName) throws Exception {
        boolean result = false;

        for (String tagName : listTagName) {
            deleteTag(tagName);
        }

        return result;

    }

    public int getTotal_searchTags(String value, String filter) throws Exception {
        int count = CounterDAO.getCounterTag(client);
        List<TagPOJO> list = searchTags(value, "0", Integer.toString(count), filter);
        return list.size();
    }

    public List<TagPOJO> searchTags(String keyWord, String start, String end, String filter) throws Exception {
        List<TagPOJO> listTag = new ArrayList<TagPOJO>();
        int _start = Integer.parseInt(start);
        int _end = Integer.parseInt(end);
        int _filter = Integer.parseInt(filter);
        ArrayList<String[]> list = (new solrSearch()).searchTags(keyWord, _start, _end, _filter);
        for (String[] strings : list) {
            TagPOJO temp = new TagPOJO();
            temp.tagName = strings[1];
            temp.createDate = strings[2];
            temp.modifyDate = strings[3];
            temp.isPublic = strings[4] == "true" ? true : false;
            listTag.add(temp);
        }
        return listTag;
    }

    public boolean insertTagInfo(String tagName, boolean state) {
        boolean result = false;
        try {
            ColumnParent parent = new ColumnParent(colParentTagInfoS);
            ByteBuffer tagNameBB = Common.GeneralHandling.toByteBuffer(tagName);
            String isPublic = (state == true) ? "public" : "private";
            client.insert(tagNameBB, parent, Common.GeneralHandling.createCol(colNameIsPublic, isPublic), Common.Constants.CL);
            client.insert(tagNameBB, parent, Common.GeneralHandling.createCol(colNameCreateDate, ""), Common.Constants.CL);
            result = true;
        } catch (InvalidRequestException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnavailableException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TimedOutException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return result;
    }

    public boolean insertListStatusInToTag(String tagName, List<String> listStatusID) {
        boolean result = false;
        try {
            ColumnParent parent = new ColumnParent(colParentListStatusS);
            ByteBuffer tagNameBB = Common.GeneralHandling.toByteBuffer(tagName);
            int numberStatus = listStatusID.size();
            for (int i = 0; i < numberStatus; i++) {
                String statusID = listStatusID.get(i);
                client.insert(tagNameBB, parent, Common.GeneralHandling.createCol(GeneralHandling.toByteBuffer(statusID), "1"), Common.Constants.CL);
            }

            result = true;
        } catch (InvalidRequestException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnavailableException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TimedOutException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return result;
    }

    private SlicePredicate createSlicePredicateForTag() {
        SlicePredicate predicate = new SlicePredicate();
        predicate.addToColumn_names(colNameCreateDate);
        predicate.addToColumn_names(colNameModifyDate);
        predicate.addToColumn_names(colNameIsPublic);
        return predicate;
    }

    private TagPOJO createTagPOJOFromListColOrSupCol(String tagName, List<ColumnOrSuperColumn> listColOrSupCol) {
        TagPOJO tag = new TagPOJO();
        tag.tagName = tagName;
        for (int j = 0; j < listColOrSupCol.size(); j++) {
            try {
                ColumnOrSuperColumn colOrSupCol = listColOrSupCol.get(j);
                Column col = colOrSupCol.column;

                if (col.name.equals(colNameCreateDate)) {
                    tag.createDate = Common.GeneralHandling.toString(col.value);
                }
                if (col.name.equals(colNameModifyDate)) {
                    tag.modifyDate = Common.GeneralHandling.toString(col.value);
                }
                if (col.name.equals(colNameIsPublic)) {
                    tag.isPublic = Common.GeneralHandling.toBool(col.value);
                }
            } catch (UnsupportedEncodingException ex) {
                Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return tag;
    }

    private List<String> getListStringStatusFromListColOrSupCol(List<ColumnOrSuperColumn> listColOrSupCol) {
        List<String> listStatusID = new ArrayList<String>();
        for (int j = 0; j < listColOrSupCol.size(); j++) {
            try {
                ColumnOrSuperColumn colOrSupCol = listColOrSupCol.get(j);
                Column col = colOrSupCol.column;
                listStatusID.add(GeneralHandling.toString(col.name));
            } catch (UnsupportedEncodingException ex) {
                Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return listStatusID;
    }
}
